let Vue

// 循环对象
function forEach(obj, callback) {
  Object.keys(obj).forEach(key => {
    callback(key, obj[key])
  })
}

class Store {
  constructor(options) {
    // 此处是为了实现响应式数据（借用Vue来实现的）
    this.vm = new Vue({
      data: {
        state: options.state
      }
    })

    let getters = options.getters // 获取用户传入的getters
    this.getters = {}
    /* Object.keys(getters).forEach(gettersName => {
      Object.defineProperty(this.getters, gettersName, {
        get: () => {
          return getters[gettersName](this.state)
        }
      })
    }) */
    forEach(getters, (key, value) => {
      // 此处的value值是一个函数(方法)
      Object.defineProperty(this.getters, key, {
        get: () => {
          return value(this.state)
        }
      })
    })

    let mutations = options.mutations
    this.mutations = {}
    forEach(mutations, (key, value) => {
      // 此处的value值是一个函数(方法)
      // this.mutations[key] = value // -> 使用该写法会报错 无法传递参数
      // 将方法给保存起来 -> 使用该种方法
      this.mutations[key] = payload => {
        // 订阅
        value(this.state, payload) // 可以进行传参
      }
    })

    let actions = options.actions
    this.actions = {}
    forEach(actions, (key, value) => {
      this.actions[key] = payload => {
        value(this, payload) // 注意这个地方的传参
      }
    })
  }
  // es6中 类的实例访问器
  get state() {
    return this.vm.state
  }

  commit = (mutationName, payload) => {
    this.mutations[mutationName](payload) // 发布
  }
  dispatch(actionName, payload) {
    this.actions[actionName](payload)
  }
}
const install = _Vue => {
  // 传递的是外部的Vueg构造函数
  // 不能直接放在Vue构造函数的原型上
  // 正确的做法：只从当前的根实开始 所有的根实例的子组件才有$store
  Vue = _Vue
  Vue.mixin({
    // 混入
    // 组件的创建过程是先父后子
    beforeCreate() {
      if (this.$options.store) {
        // 根实例
        this.$store = this.$options.store
      } else {
        this.$store = this.$parent && this.$parent.$store
      }
    }
  })
}

export default {
  Store,
  install
}
